using System;
using System.Collections.Generic;
using JetBrains.DocumentModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Daemon.UsageChecking;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;

namespace Sapphire.RSharp.Common
{
  public static class Extensions
  {
    public static CollectUsagesStageProcess GetCollectUsagesStageProcess(this IDaemonProcess process)
    {
      foreach (var stageProcess in process.GetCompletedStageProcesses())
      {
        if (stageProcess.GetType()
          .IsSubclassOf(typeof(CollectUsagesStageProcess)))
        {
          return (CollectUsagesStageProcess)stageProcess;
        }
      }

      return process.GetStageProcess<CollectUsagesStageProcess>();
    }

    public static bool InUsing(this ICreationExpression element)
    {
      return element.ToTreeNode().ChildOf<IUsingStatement>();
    }

    public static bool ChildOf<T>(this ITreeNode treeNode)
    {
      if (treeNode == null)
        return false;

      if (treeNode is T)
        return true;

      return ChildOf<T>(treeNode.Parent);
    }

    public static bool IsDisposed(this ICreationExpression element,
      CollectUsagesStageProcess usagesProcess)
    {
      var el = element.GetContainingStatement()
        .GetContainingElement(typeof(IDeclaredElement), true);
      return false;
    }

    public static bool IsDisposed(this ICollection<IElement> elements)
    {
      foreach (var element in elements)
      {
        var usage = element.ToTreeNode().Parent.GetText()
          .Replace(element.GetText(), string.Empty);
        if (usage.Equals(".Close", StringComparison.InvariantCultureIgnoreCase))
          return true;
      }
      return false;
    }

    public static void RemoveChild(this IList<IElement> elements,
      IElement elementToRemove)
    {
      var resultElements = new List<IElement>();

      foreach (var element in elements)
      {
        if (elementToRemove.Contains(element))
        {
          resultElements.Add(element);
        }
      }

      foreach (var element in resultElements)
      {
        elements.Remove(element);
      }
    }

    public static DocumentRange GetDetectedDocumentRange(this IElement element)
    {
      if (element is IObjectCreationExpression)
      {
        return element.ToTreeNode()
          .Parent.Parent.Parent.Parent.GetDocumentRange();
      }

      return element.GetDocumentRange();
    }
  }
}